home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / misc / sci / ephem_src_4_28.lha / main.c < prev    next >
C/C++ Source or Header  |  1992-05-28  |  26KB  |  1,049 lines

  1. /* main "ephem" program. 
  2.  * -------------------------------------------------------------------
  3.  * Copyright (c) 1990,1991,1992 by Elwood Charles Downey
  4.  * 
  5.  * Permission is granted to make and distribute copies of this program
  6.  * free of charge, provided the copyright notice and this permission
  7.  * notice are preserved on all copies.  All other rights reserved.
  8.  * -------------------------------------------------------------------
  9.  * set options.
  10.  * init screen and circumstances.
  11.  * enter infinite loop updating screen and allowing operator input.
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <signal.h>
  17. #include <setjmp.h>
  18. #include <math.h>
  19. #ifdef VMS
  20. #include <stdlib.h>
  21. #endif
  22. #include "astro.h"
  23. #include "circum.h"
  24. #include "screen.h"
  25.  
  26. extern char *strncpy();
  27. #ifdef AMIGA
  28. extern char *wgetenv();
  29. #else
  30. extern char *getenv();
  31. #endif
  32.  
  33. /* shorthands for fields of a Now structure, now.
  34.  * first undo the ones for a Now pointer from circum.h.
  35.  */
  36. #undef mjd
  37. #undef lat
  38. #undef lng
  39. #undef tz
  40. #undef temp
  41. #undef pressure
  42. #undef height
  43. #undef epoch
  44. #undef tznm
  45.  
  46. #define mjd    now.n_mjd
  47. #define lat    now.n_lat
  48. #define lng    now.n_lng
  49. #define tz    now.n_tz
  50. #define temp    now.n_temp
  51. #define pressure now.n_pressure
  52. #define height    now.n_height
  53. #define epoch    now.n_epoch
  54. #define tznm    now.n_tznm
  55.  
  56. static jmp_buf fpe_err_jmp;    /* used to recover from SIGFPE */
  57. static char *cfgfile;        /* !0 if -c used */
  58. #ifdef AMIGA
  59. static char cfgdef[] = "S:ephem.cfg"; /* default configuration file name */
  60. #else
  61. static char cfgdef[] = "ephem.cfg"; /* default configuration file name */
  62. #endif
  63. static Now now;        /* where when and how, right now */
  64. static double tminc;    /* hrs to inc time by each loop; RTC means use clock */
  65. static int nstep;    /* steps to go before stopping */
  66. static int spause;    /* secs to pause between steps */
  67. static int optwi;    /* set when want to display dawn/dusk/len-of-night */
  68. static int oppl;    /* mask of (1<<planet) bits; set when want to show it */
  69.  
  70. main (ac, av)
  71. int ac;
  72. char *av[];
  73. {
  74.     void bye();
  75.     void on_fpe();
  76.     static char freerun[] =
  77.         "Running... press any key to stop to make changes.";
  78.     static char prmpt[] =
  79. "Move to another field, RETURN to change this field, ? for help, or q to run";
  80.     static char hlp[] =
  81.     "arrow keys move to field; any key stops running; ^d exits; ^l redraws";
  82.     int fld = rcfpack(R_NSTEP, C_NSTEPV, 0); /* initial cursor loc */
  83.     int sflag = 0;    /* not silent, by default */
  84.     int one = 1;    /* use a variable so optimizer doesn't get disabled */
  85.     int srchdone = 0; /* true when search funcs say so */
  86.     int newcir = 2;    /* set when circumstances change - means don't tminc */
  87.  
  88.     while ((--ac > 0) && (**++av == '-')) {
  89.         char *s;
  90.         for (s = *av+1; *s != '\0'; s++)
  91.         switch (*s) {
  92.         case 's': /* no credits "silent" (don't publish this) */
  93.             sflag++;
  94.             break;
  95.         case 'c': /* set name of config file to use */
  96.             if (--ac <= 0) usage("-c but no config file");
  97.             cfgfile = *++av;
  98.             break;
  99.         case 'd': /* set alternate database file name */
  100.             if (--ac <= 0) usage("-d but no database file");
  101.             obj_setdbfilename (*++av);
  102.             break;
  103.         default:
  104.             usage("Bad - option");
  105.         }
  106.     }
  107.  
  108.     if (!sflag)
  109.         credits();
  110.  
  111.     /* fresh screen.
  112.      * crack config file, THEN args so args may override.
  113.      */
  114.     c_erase();
  115.     read_cfgfile ();
  116.     read_fieldargs (ac, av);
  117.  
  118.     /* set up to clean up screen and tty if interrupted.
  119.      * also set up to stop if get floating error.
  120.      */
  121.     (void) signal (SIGINT, bye);
  122.     (void) signal (SIGFPE, on_fpe);
  123.  
  124.     /* update screen forever (until QUIT) */
  125.     while (one) {
  126.  
  127.         /* if get a floating error, longjmp() here and stop looping */
  128.         if (setjmp (fpe_err_jmp))
  129.         nstep = 0;
  130.         else {
  131.         nstep -= 1;
  132.  
  133.         /* recalculate everything and update all the fields */
  134.         redraw_screen (newcir);
  135.         mm_newcir (0);
  136.  
  137.         /* let searching functions change tminc and check for done */
  138.         srchdone = srch_eval (mjd, &tminc) < 0;
  139.         print_tminc(0);    /* to show possibly new search increment */
  140.  
  141.         /* update plot and listing files, now that all fields are up
  142.          * to date and search function has been evaluated.
  143.          */
  144.         plot();
  145.         listing();
  146.  
  147.         /* handle spause if we are really looping */
  148.         if (nstep > 0)
  149.             slp_sync();
  150.         }
  151.  
  152.         /* stop loop to allow op to change parameters:
  153.          * if a search evaluation converges (or errors out),
  154.          * or if steps are done,
  155.          * or if op hits any key.
  156.          */
  157.         newcir = 0;
  158.         if (srchdone || nstep <= 0 || (chk_char()==0 && read_char()!=0)) {
  159.         int nfld;
  160.  
  161.         /* update screen with the current stuff if stopped during
  162.          * unattended plotting or listing since last redraw_screen()
  163.          * didn't.
  164.          */
  165.         if ((plot_ison() || listing_ison()) && nstep > 0)
  166.             redraw_screen (1);
  167.  
  168.         /* return nstep to default of 1 */
  169.         if (nstep <= 0) {
  170.             nstep = 1;
  171.             print_nstep (0);
  172.         }
  173.  
  174.         /* change fields until END.
  175.          * update all time fields if any are changed
  176.          * and print NEW CIRCUMSTANCES if any have changed.
  177.          * QUIT causes bye() to be called and we never return.
  178.          */
  179.         while(nfld = sel_fld(fld,alt_menumask()|F_CHG,prmpt,hlp)) {
  180.             if (chg_fld ((char *)0, &nfld)) {
  181.             mm_now (&now, 1);
  182.             mm_newcir(1);
  183.             newcir = 1;
  184.             }
  185.             fld = nfld;
  186.         }
  187.         if (nstep > 1)
  188.             f_prompt (freerun);
  189.         }
  190.  
  191.         /* increment time only if op didn't change cirumstances */
  192.         if (!newcir)
  193.         inc_mjd (&now, tminc);
  194.     }
  195.  
  196.     return (0);
  197. }
  198.  
  199. /* read in ephem's configuration file, if any.
  200.  * if errors in file, call usage() (which exits).
  201.  * if use -d, require it; else try $EPHEMCFG and ephem.cfg but don't
  202.  *   complain if can't find these since, after all, one is not required.
  203.  * skip all lines that doesn't begin with an alpha char.
  204.  */
  205. static
  206. read_cfgfile()
  207. {
  208.     char buf[128];
  209.     FILE *fp;
  210.     char *fn;
  211.  
  212.     /* open the config file. 
  213.      * only REQUIRED if used -d option.
  214.      * if succcessful, fn points to file name.
  215.      */
  216.     if (cfgfile) {
  217.         fn = cfgfile;
  218.         fp = fopen (fn, "r");
  219.         if (!fp) {
  220.         (void) sprintf (buf, "Can not open %s", fn);
  221.         usage (buf);    /* does not return */
  222.         }
  223.     } else {
  224. #ifdef AMIGA
  225.         fn = wgetenv ("EPHEMCFG");
  226. #else
  227.         fn = getenv ("EPHEMCFG");
  228. #endif
  229.         if (!fn)
  230.         fn = cfgdef;
  231.     }
  232.     fp = fopen (fn, "r");
  233.     if (!fp)
  234.         return;    /* oh well; after all, it's not required */
  235.  
  236.     while (fgets (buf, sizeof(buf), fp)) {
  237.         if (!isalpha(buf[0]))
  238.         continue;
  239.         buf[strlen(buf)-1] = '\0';        /* discard trailing \n */
  240.         if (crack_fieldset (buf) < 0) {
  241.         char why[NC];
  242.         (void) sprintf (why, "Bad field spec in %s: %s\n", fn, buf);
  243.         usage (why);
  244.         }
  245.     }
  246.     (void) fclose (fp);
  247. }
  248.  
  249.  
  250. /* draw all the stuff on the screen, using the current menu.
  251.  * if how_much == 0 then just update fields that need it;
  252.  * if how_much == 1 then redraw all fields;
  253.  * if how_much == 2 then erase the screen and redraw EVERYTHING.
  254.  */
  255. redraw_screen (how_much)
  256. int how_much;
  257. {
  258.     if (how_much == 2)
  259.         c_erase();
  260.  
  261.     /* print the single-step message if this is the last loop */
  262.     if (nstep < 1)
  263.         print_updating();
  264.  
  265.     if (how_much == 2) {
  266.         mm_borders();
  267.         mm_labels();
  268.         srch_prstate(1);
  269.         plot_prstate(1);
  270.         listing_prstate(1);
  271.     }
  272.  
  273.     /* if just updating changed fields while plotting or listing
  274.      * unattended then suppress most screen updates except
  275.      * always show nstep to show plot loops to go and
  276.      * always show tminc to show search convergence progress.
  277.      */
  278.     print_nstep(how_much);
  279.     print_tminc(how_much);
  280.     print_spause(how_much);
  281.     if (how_much == 0 && (plot_ison() || listing_ison()) && nstep > 0)
  282.         f_off();
  283.  
  284.     /* print all the time-related fields */
  285.     mm_now (&now, how_much);
  286.  
  287.     if (optwi)
  288.         mm_twilight (&now, how_much);
  289.  
  290.     /* print stuff on bottom menu */
  291.     print_alt (how_much);
  292.  
  293.     f_on();
  294. }
  295.  
  296. /* clean up and exit.
  297.  */
  298. void
  299. bye()
  300. {
  301.     c_erase();
  302.     byetty();
  303.     exit (0);
  304. }
  305.  
  306. /* this gets called when a floating point error occurs.
  307.  * we force a jump back into main() with looping terminated.
  308.  */
  309. static
  310. void
  311. on_fpe()
  312. {
  313.     extern void longjmp();
  314.  
  315.     (void) signal (SIGFPE, on_fpe);
  316.     f_msg ("Floating point error has occurred - computations aborted.");
  317.     longjmp (fpe_err_jmp, 1);
  318. }
  319.  
  320. usage(why)
  321. char *why;
  322. {
  323.     /* don't advertise -s (silent) option */
  324.     c_erase();
  325.     f_string (1, 1, why);
  326.     f_string (2, 1,
  327.         "usage: [-c <configfile>] [-d <database>] [field=value ...]\r\n");
  328.     byetty();
  329.     exit (1);
  330. }
  331.  
  332. /* process the field specs from the command line.
  333.  * if trouble call usage() (which exits).
  334.  */
  335. static
  336. read_fieldargs (ac, av)
  337. int ac;        /* number of such specs */
  338. char *av[];    /* array of strings in form <field_name value> */
  339. {
  340.     while (--ac >= 0) {
  341.         char *fs = *av++;
  342.         if (crack_fieldset (fs) < 0) {
  343.         char why[NC];
  344.         (void) sprintf (why, "Bad command line spec: %.*s",
  345.                             sizeof(why)-26, fs);
  346.         usage (why);
  347.         }
  348.     }
  349. }
  350.  
  351. /* process a field spec in buf, either from config file or argv.
  352.  * return 0 if recognized ok, else -1.
  353.  */
  354. static
  355. crack_fieldset (buf)
  356. char *buf;
  357. {
  358. #define    ARRAY_SIZ(a)    (sizeof(a)/sizeof((a)[0]))
  359. #define    MAXKW        6    /* longest keyword, not counting trailing 0 */
  360.     /* N.B. index of item is its case value, below.
  361.      * N.B. if add an item, keep it no longer than MAXKW chars.
  362.      */
  363.     static char keywords[][MAXKW+1] = {
  364.         /*  0 */    "LAT",
  365.         /*  1 */    "LONG",
  366.         /*  2 */    "UT",
  367.         /*  3 */    "UD",
  368.         /*  4 */    "TZONE",
  369.         /*  5 */    "TZNAME",
  370.         /*  6 */    "HEIGHT",
  371.         /*  7 */    "NSTEP",
  372.         /*  8 */    "PAUSE",
  373.         /*  9 */    "STPSZ",
  374.         /* 10 */    "TEMP",
  375.         /* 11 */    "PRES",
  376.         /* 12 */    "EPOCH",
  377.         /* 13 */    "JD",
  378.         /* 14 */    "OBJX",
  379.         /* 15 */    "OBJY",
  380.         /* 16 */    "PROPTS",
  381.         /* 17 */    "MENU"
  382.     };
  383.     int i;
  384.     int l;
  385.     int f;
  386.  
  387.     for (i = 0; i < ARRAY_SIZ(keywords); i++)
  388.         if (strncmp (keywords[i], buf, l = strlen(keywords[i])) == 0) {
  389.         buf += l+1;    /* skip keyword and its subsequent delimiter */
  390.         break;
  391.         }
  392.  
  393.     switch (i) {
  394.     case 0: f = rcfpack (R_LAT,C_LATV,0); (void) chg_fld (buf, &f);
  395.         break;
  396.     case 1: f = rcfpack (R_LONG,C_LONGV,0), (void) chg_fld (buf, &f);
  397.         break;
  398.     case 2: f = rcfpack (R_UT,C_UTV,0), (void) chg_fld (buf, &f);
  399.         break;
  400.     case 3: f = rcfpack (R_UD,C_UD,0), (void) chg_fld (buf, &f);
  401.         break;
  402.     case 4: f = rcfpack (R_TZONE,C_TZONEV,0), (void) chg_fld (buf, &f);
  403.         break;
  404.     case 5: f = rcfpack (R_TZN,C_TZN,0), (void) chg_fld (buf, &f);
  405.         break;
  406.     case 6: f = rcfpack (R_HEIGHT,C_HEIGHTV,0), (void) chg_fld (buf, &f);
  407.         break;
  408.     case 7: f = rcfpack (R_NSTEP,C_NSTEPV,0), (void) chg_fld (buf, &f);
  409.         break;
  410.     case 8: f = rcfpack (R_PAUSE,C_PAUSEV,0), (void) chg_fld (buf, &f);
  411.         break;
  412.     case 9: f = rcfpack (R_STPSZ,C_STPSZV,0), (void) chg_fld (buf, &f);
  413.         break;
  414.     case 10: f = rcfpack (R_TEMP,C_TEMPV,0), (void) chg_fld (buf, &f);
  415.         break;
  416.     case 11: f = rcfpack (R_PRES,C_PRESV,0), (void) chg_fld (buf, &f);
  417.         break;
  418.     case 12: f = rcfpack (R_EPOCH,C_EPOCHV,0), (void) chg_fld (buf, &f);
  419.         break;
  420.     case 13: f = rcfpack (R_JD,C_JDV,0), (void) chg_fld (buf, &f);
  421.         break;
  422.     case 14: (void) obj_filelookup (OBJX, buf);
  423.         break;
  424.     case 15: (void) obj_filelookup (OBJY, buf);
  425.         break;
  426.     case 16:
  427.         if (buf[-1] != '+')
  428.         optwi = oppl = 0;
  429.         while (*buf)
  430.         switch (*buf++) {
  431.         case 'T': optwi = 1; break;
  432.         case 'S': oppl |= (1<<SUN); break;
  433.         case 'M': oppl |= (1<<MOON); break;
  434.         case 'e': oppl |= (1<<MERCURY); break;
  435.         case 'v': oppl |= (1<<VENUS); break;
  436.         case 'm': oppl |= (1<<MARS); break;
  437.         case 'j': case 'J': oppl |= (1<<JUPITER); break;
  438.         case 's': oppl |= (1<<SATURN); break;
  439.         case 'u': oppl |= (1<<URANUS); break;
  440.         case 'n': oppl |= (1<<NEPTUNE); break;
  441.         case 'p': oppl |= (1<<PLUTO); break;
  442.         case 'x': oppl |= (1<<OBJX); obj_on(OBJX); break;
  443.         case 'y': oppl |= (1<<OBJY); obj_on(OBJY); break;
  444.         }
  445.         break;
  446.     case 17:
  447.         if (strncmp (buf, "DATA", 4) == 0)
  448.         altmenu_init (F_MNU1);
  449.         else if (strncmp (buf, "RISET", 5) == 0)
  450.         altmenu_init (F_MNU2);
  451.         else if (strncmp (buf, "SEP", 3) == 0)
  452.         altmenu_init (F_MNU3);
  453.         else if (strncmp (buf, "JUP", 3) == 0)
  454.         altmenu_init (F_MNUJ);
  455.         break;
  456.     default:
  457.         return (-1);
  458.     }
  459.     return (0);
  460. }
  461.  
  462. /* react to the field at *fld according to the optional string input at bp.
  463.  * if bp is != 0 use it, else issue read_line() and use buffer.
  464.  * then sscanf the buffer and update the corresponding (global) variable(s)
  465.  * or do whatever a pick at that field should do.
  466.  * we might also change *fld if we want to change the current cursor location.
  467.  * return 1 if we change a field that invalidates any of the times or
  468.  * to update all related fields.
  469.  */
  470. static
  471. chg_fld (bp, fld)
  472. char *bp;
  473. int *fld;
  474. {
  475.     char buf[NC];
  476.     int deghrs = 0, mins = 0, secs = 0;
  477.     int new = 0;
  478.  
  479.     /* switch on just the row/col portion */
  480.     switch (unpackrc(*fld)) {
  481.     case rcfpack (R_ALTM, C_ALTM, 0):
  482.         if (altmenu_setup() == 0) {
  483.         print_updating();
  484.         alt_erase();
  485.         print_alt(2);
  486.         }
  487.         break;
  488.     case rcfpack (R_JD, C_JDV, 0):
  489.         if (!bp) {
  490.         static char p[] = "Julian Date (or n for Now): ";
  491.         f_prompt (p);
  492.         if (read_line (buf, PW-sizeof(p)) <= 0)
  493.             break;
  494.         bp = buf;
  495.         }
  496.         if (bp[0] == 'n' || bp[0] == 'N')
  497.         time_fromsys (&now);
  498.         else
  499.         mjd = atof(bp) - 2415020L;
  500.         set_t0 (&now);
  501.         new = 1;
  502.         break;
  503.     case rcfpack (R_UD, C_UD, 0):
  504.         if (!bp) {
  505.         static char p[] = "utc date (m/d/y, or year.d, or n for Now): ";
  506.         f_prompt (p);
  507.         if (read_line (buf, PW-sizeof(p)) <= 0)
  508.             break;
  509.         bp = buf;
  510.         }
  511.         if (bp[0] == 'n' || bp[0] == 'N')
  512.         time_fromsys (&now);
  513.         else {
  514.         if (decimal_year(bp)) {
  515.             double y = atof (bp);
  516.             year_mjd (y, &mjd);
  517.         } else {
  518.             double day, newmjd0;
  519.             int month, year;
  520.             mjd_cal (mjd, &month, &day, &year); /* init with now */
  521.             f_sscandate (bp, &month, &day, &year);
  522.             cal_mjd (month, day, year, &newmjd0);
  523.             /* if don't give a fractional part to days
  524.              * then retain current hours.
  525.              */
  526.             if ((long)day == day)
  527.             mjd = newmjd0 + mjd_hr(mjd)/24.0;
  528.             else
  529.             mjd = newmjd0;
  530.         }
  531.         }
  532.         set_t0 (&now);
  533.         new = 1;
  534.         break;
  535.     case rcfpack (R_UT, C_UTV, 0):
  536.         if (!bp) {
  537.         static char p[] = "utc time (h:m:s, or n for Now): ";
  538.         f_prompt (p);
  539.         if (read_line (buf, PW-sizeof(p)) <= 0)
  540.             break;
  541.         bp = buf;
  542.         }
  543.         if (bp[0] == 'n' || bp[0] == 'N')
  544.         time_fromsys (&now);
  545.         else {
  546.         double newutc = (mjd-mjd_day(mjd)) * 24.0;
  547.         f_dec_sexsign (newutc, °hrs, &mins, &secs);
  548.         f_sscansex (bp, °hrs, &mins, &secs);
  549.         sex_dec (deghrs, mins, secs, &newutc);
  550.         mjd = mjd_day(mjd) + newutc/24.0;
  551.         }
  552.         set_t0 (&now);
  553.         new = 1;
  554.         break;
  555.     case rcfpack (R_LD, C_LD, 0):
  556.         if (!bp) {
  557.         static char p[] = "local date (m/d/y, or year.d, n for Now): ";
  558.         f_prompt (p);
  559.         if (read_line (buf, PW-sizeof(p)) <= 0)
  560.             break;
  561.         bp = buf;
  562.         }
  563.         if (bp[0] == 'n' || bp[0] == 'N')
  564.         time_fromsys (&now);
  565.         else {
  566.         if (decimal_year(bp)) {
  567.             double y = atof (bp);
  568.             year_mjd (y, &mjd);
  569.             mjd += tz/24.0;
  570.         } else {
  571.             double day, newlmjd0;
  572.             int month, year;
  573.             mjd_cal (mjd-tz/24.0, &month, &day, &year); /* now */
  574.             f_sscandate (bp, &month, &day, &year);
  575.             cal_mjd (month, day, year, &newlmjd0);
  576.             /* if don't give a fractional part to days
  577.              * then retain current hours.
  578.              */
  579.             if ((long)day == day)
  580.             mjd = newlmjd0 + mjd_hr(mjd-tz/24.0)/24.0;
  581.             else
  582.             mjd = newlmjd0;
  583.             mjd += tz/24.0;
  584.         }
  585.         }
  586.         set_t0 (&now);
  587.         new = 1;
  588.         break;
  589.     case rcfpack (R_LT, C_LT, 0):
  590.         if (!bp) {
  591.         static char p[] = "local time (h:m:s, or n for Now): ";
  592.         f_prompt (p);
  593.         if (read_line (buf, PW-sizeof(p)) <= 0)
  594.             break;
  595.         bp = buf;
  596.         }
  597.         if (bp[0] == 'n' || bp[0] == 'N')
  598.         time_fromsys (&now);
  599.         else {
  600.         double newlt = (mjd-mjd_day(mjd)) * 24.0 - tz;
  601.         range (&newlt, 24.0);
  602.         f_dec_sexsign (newlt, °hrs, &mins, &secs);
  603.         f_sscansex (bp, °hrs, &mins, &secs);
  604.         sex_dec (deghrs, mins, secs, &newlt);
  605.         mjd = mjd_day(mjd-tz/24.0) + (newlt + tz)/24.0;
  606.         }
  607.         set_t0 (&now);
  608.         new = 1;
  609.         break;
  610.     case rcfpack (R_LST, C_LSTV, 0):
  611.         if (!bp) {
  612.         static char p[] = "local sidereal time (h:m:s, or n for Now): ";
  613.         f_prompt (p);
  614.         if (read_line (buf, PW-sizeof(p)) <= 0)
  615.             break;
  616.         bp = buf;
  617.         }
  618.         if (bp[0] == 'n' || bp[0] == 'N')
  619.         time_fromsys (&now);
  620.         else {
  621.         double lst, utc;
  622.         now_lst (&now, &lst);
  623.         f_dec_sexsign (lst, °hrs, &mins, &secs);
  624.         f_sscansex (bp, °hrs, &mins, &secs);
  625.         sex_dec (deghrs, mins, secs, &lst);
  626.         lst -= radhr(lng); /* convert to gst */
  627.         range (&lst, 24.0);
  628.         gst_utc (mjd_day(mjd), lst, &utc);
  629.         mjd = mjd_day(mjd) + utc/24.0;
  630.         }
  631.         set_t0 (&now);
  632.         new = 1;
  633.         break;
  634.     case rcfpack (R_TZN, C_TZN, 0):
  635.         if (!bp) {
  636.         static char p[] = "timezone abbreviation (3 char max): ";
  637.         f_prompt (p);
  638.         if (read_line (buf, 3) <= 0)
  639.             break;
  640.         bp = buf;
  641.         }
  642.         (void) strncpy (tznm, bp, sizeof(tznm)-1);
  643.         new = 1;
  644.         break;
  645.     case rcfpack (R_TZONE, C_TZONEV, 0):
  646.         if (!bp) {
  647.         static char p[] = "hours behind utc: ";
  648.         f_prompt (p);
  649.         if (read_line (buf, PW-sizeof(p)) <= 0)
  650.             break;
  651.         bp = buf;
  652.         }
  653.         f_dec_sexsign (tz, °hrs, &mins, &secs);
  654.         f_sscansex (bp, °hrs, &mins, &secs);
  655.         sex_dec (deghrs, mins, secs, &tz);
  656.         new = 1;
  657.         break;
  658.     case rcfpack (R_LONG, C_LONGV, 0):
  659.         if (!bp) {
  660.         static char p[] = "longitude (+ west) (d:m:s): ";
  661.         f_prompt (p);
  662.         if (read_line (buf, PW-sizeof(p)) <= 0)
  663.             break;
  664.         bp = buf;
  665.         }
  666.         f_dec_sexsign (-raddeg(lng), °hrs, &mins, &secs);
  667.         f_sscansex (bp, °hrs, &mins, &secs);
  668.         sex_dec (deghrs, mins, secs, &lng);
  669.         lng = degrad (-lng);         /* want - radians west */
  670.         new = 1;
  671.         break;
  672.     case rcfpack (R_LAT, C_LATV, 0):
  673.         if (!bp) {
  674.         static char p[] = "latitude (+ north) (d:m:s): ";
  675.         f_prompt (p);
  676.         if (read_line (buf, PW-sizeof(p)) <= 0)
  677.             break;
  678.         bp = buf;
  679.         }
  680.         f_dec_sexsign (raddeg(lat), °hrs, &mins, &secs);
  681.         f_sscansex (bp, °hrs, &mins, &secs);
  682.         sex_dec (deghrs, mins, secs, &lat);
  683.         lat = degrad (lat);
  684.         new = 1;
  685.         break;
  686.     case rcfpack (R_HEIGHT, C_HEIGHTV, 0):
  687.         if (!bp) {
  688.         static char p[] = "height above sea level (ft): ";
  689.         f_prompt (p);
  690.         if (read_line (buf, PW-sizeof(p)) <= 0)
  691.             break;
  692.         bp = buf;
  693.         }
  694.         if (sscanf (bp, "%lf", &height) == 1) {
  695.         height /= 2.093e7; /*convert ft to earth radii above sea level*/
  696.         new = 1;
  697.         }
  698.         break;
  699.     case rcfpack (R_NSTEP, C_NSTEPV, 0):
  700.         if (!bp) {
  701.         static char p[] = "number of steps to run: ";
  702.         f_prompt (p);
  703.         if (read_line (buf, 8) <= 0)
  704.             break;
  705.         bp = buf;
  706.         }
  707.         (void) sscanf (bp, "%d", &nstep);
  708.         print_nstep (0);
  709.         break;
  710.     case rcfpack (R_PAUSE, C_PAUSEV, 0):
  711.         if (!bp) {
  712.         static char p[] = "seconds to pause between steps: ";
  713.         f_prompt (p);
  714.         if (read_line (buf, 8) <= 0)
  715.             break;
  716.         bp = buf;
  717.         }
  718.         (void) sscanf (bp, "%d", &spause);
  719.         print_spause (0);
  720.         break;
  721.     case rcfpack (R_TEMP, C_TEMPV, 0):
  722.         if (!bp) {
  723.         static char p[] = "temperature (deg.F): ";
  724.         f_prompt (p);
  725.         if (read_line (buf, PW-sizeof(p)) <= 0)
  726.             break;
  727.         bp = buf;
  728.         }
  729.         if (sscanf (bp, "%lf", &temp) == 1) {
  730.         temp = 5./9.*(temp - 32.0);    /* want degs C */
  731.         new = 1;
  732.         }
  733.         break;
  734.     case rcfpack (R_PRES, C_PRESV, 0):
  735.         if (!bp) {
  736.         static char p[] =
  737.             "atmos pressure (in. Hg; 0 for no refraction correction): ";
  738.         f_prompt (p);
  739.         if (read_line (buf, PW-sizeof(p)) <= 0)
  740.             break;
  741.         bp = buf;
  742.         }
  743.         if (sscanf (bp, "%lf", &pressure) == 1) {
  744.         pressure *= 33.86;        /* want mBar */
  745.         new = 1;
  746.         }
  747.         break;
  748.     case rcfpack (R_EPOCH, C_EPOCHV, 0):
  749.         if (!bp) {
  750.         static char p[] = "epoch (year, or e for Equinox of Date): ";
  751.         f_prompt (p);
  752.         if (read_line (buf, PW-strlen(p)) <= 0)
  753.             break;
  754.         bp = buf;
  755.         }
  756.         if (bp[0] == 'e' || bp[0] == 'E')
  757.         epoch = EOD;
  758.         else {
  759.         double e;
  760.         e = atof(bp);
  761.         year_mjd (e, &epoch);
  762.         }
  763.         new = 1;
  764.         break;
  765.     case rcfpack (R_STPSZ, C_STPSZV, 0):
  766.         if (!bp) {
  767.         static char p[] =
  768.             "step size increment (h:m:s, or <x>d for x days, or r for RTC): ";
  769.         f_prompt (p);
  770.         if (read_line (buf, PW-sizeof(p)) <= 0)
  771.             break;
  772.         bp = buf;
  773.         }
  774.         if (bp[0] == 'r' || bp[0] == 'R')
  775.         tminc = RTC;
  776.         else {
  777.         int last = strlen (bp) - 1;
  778.         if (bp[last] == 'd') {
  779.             /* ends in d so treat as a number of days */
  780.             double x;
  781.             if (sscanf (bp, "%lf", &x) == 1)
  782.             tminc = x * 24.0;
  783.         } else {
  784.             if (tminc == RTC)
  785.             deghrs = mins = secs = 0;
  786.             else
  787.             f_dec_sexsign (tminc, °hrs, &mins, &secs);
  788.             f_sscansex (bp, °hrs, &mins, &secs);
  789.             sex_dec (deghrs, mins, secs, &tminc);
  790.         }
  791.         }
  792.         print_tminc(0);
  793.         set_t0 (&now);
  794.         break;
  795.     case rcfpack (R_PLOT, C_PLOT, 0):
  796.         plot_setup();
  797.         if (plot_ison())
  798.         new = 1;
  799.         break;
  800.     case rcfpack (R_LISTING, C_LISTING, 0):
  801.         listing_setup();
  802.         if (listing_ison())
  803.         new = 1;
  804.         break;
  805.     case rcfpack (R_WATCH, C_WATCH, 0):
  806.         watch (&now, tminc, oppl);
  807.         /* set new reference time to what watch left it.
  808.          * no need to set new since watch just did a redraw.
  809.          */
  810.         set_t0 (&now);
  811.         break;
  812.     case rcfpack (R_DAWN, C_DAWN, 0):
  813.     case rcfpack (R_DUSK, C_DUSK, 0):
  814.     case rcfpack (R_LON, C_LON, 0):
  815.         if (optwi ^= 1) {
  816.         print_updating();
  817.         mm_twilight (&now, 1);
  818.         } else {
  819.         f_blanks (R_DAWN, C_DAWNV, 5);
  820.         f_blanks (R_DUSK, C_DUSKV, 5);
  821.         f_blanks (R_LON, C_LONV, 5);
  822.         }
  823.         break;
  824.     case rcfpack (R_SRCH, C_SRCH, 0):
  825.         srch_setup();
  826.         if (srch_ison())
  827.         new = 1;
  828.         break;
  829.     case rcfpack (R_SUN, C_OBJ, 0):
  830.         toggle_body (SUN);
  831.         break;
  832.     case rcfpack (R_SUN, C_CONSTEL, 0):
  833.         if (oppl & (1<<SUN))
  834.         constellation_msg (SUN, &now);
  835.         break;
  836.     case rcfpack (R_MOON, C_OBJ, 0):
  837.         toggle_body (MOON);
  838.         break;
  839.     case rcfpack (R_MOON, C_CONSTEL, 0):
  840.         if (oppl & (1<<MOON))
  841.         constellation_msg (MOON, &now);
  842.         break;
  843.     case rcfpack (R_MERCURY, C_OBJ, 0):
  844.         toggle_body (MERCURY);
  845.         break;
  846.     case rcfpack (R_MERCURY, C_CONSTEL, 0):
  847.         if (oppl & (1<<MERCURY))
  848.         constellation_msg (MERCURY, &now);
  849.         break;
  850.     case rcfpack (R_VENUS, C_OBJ, 0):
  851.         toggle_body (VENUS);
  852.         break;
  853.     case rcfpack (R_VENUS, C_CONSTEL, 0):
  854.         if (oppl & (1<<VENUS))
  855.         constellation_msg (VENUS, &now);
  856.         break;
  857.     case rcfpack (R_MARS, C_OBJ, 0):
  858.         toggle_body (MARS);
  859.         break;
  860.     case rcfpack (R_MARS, C_CONSTEL, 0):
  861.         if (oppl & (1<<MARS))
  862.         constellation_msg (MARS, &now);
  863.         break;
  864.     case rcfpack (R_JUPITER, C_OBJ, 0):
  865.         toggle_body (JUPITER);
  866.         break;
  867.     case rcfpack (R_JUPITER, C_CONSTEL, 0):
  868.         if (oppl & (1<<JUPITER))
  869.         constellation_msg (JUPITER, &now);
  870.         break;
  871.     case rcfpack (R_JUPITER, C_XTRA, 0):
  872.         if (oppl & (1<<JUPITER)) {
  873.         print_updating();
  874.         alt_erase();
  875.         altmenu_init (F_MNUJ);
  876.         print_alt (2);
  877.         *fld = rcfpack(R_NSTEP, C_NSTEPV, 0);
  878.         }
  879.         break;
  880.     case rcfpack (R_SATURN, C_OBJ, 0):
  881.         toggle_body (SATURN);
  882.         break;
  883.     case rcfpack (R_SATURN, C_CONSTEL, 0):
  884.         if (oppl & (1<<SATURN))
  885.         constellation_msg (SATURN, &now);
  886.         break;
  887.     case rcfpack (R_URANUS, C_OBJ, 0):
  888.         toggle_body (URANUS);
  889.         break;
  890.     case rcfpack (R_URANUS, C_CONSTEL, 0):
  891.         if (oppl & (1<<URANUS))
  892.         constellation_msg (URANUS, &now);
  893.         break;
  894.     case rcfpack (R_NEPTUNE, C_OBJ, 0):
  895.         toggle_body (NEPTUNE);
  896.         break;
  897.     case rcfpack (R_NEPTUNE, C_CONSTEL, 0):
  898.         if (oppl & (1<<NEPTUNE))
  899.         constellation_msg (NEPTUNE, &now);
  900.         break;
  901.     case rcfpack (R_PLUTO, C_OBJ, 0):
  902.         toggle_body (PLUTO);
  903.         break;
  904.     case rcfpack (R_PLUTO, C_CONSTEL, 0):
  905.         if (oppl & (1<<PLUTO))
  906.         constellation_msg (PLUTO, &now);
  907.         break;
  908.     case rcfpack (R_OBJX, C_OBJ, 0):
  909.         /* this might change which columns are used so erase all when
  910.          * returns and redraw if still on.
  911.          */
  912.         obj_setup (OBJX);
  913.         alt_nobody (OBJX);
  914.         if (obj_ison (OBJX)) {
  915.         oppl |= 1 << OBJX;
  916.         print_updating();
  917.         alt_body (OBJX, 1, &now);
  918.         } else
  919.         oppl &= ~(1 << OBJX);    /* already erased; just clear flag */
  920.         break;
  921.     case rcfpack (R_OBJX, C_CONSTEL, 0):
  922.         if (oppl & (1<<OBJX))
  923.         constellation_msg (OBJX, &now);
  924.         break;
  925.     case rcfpack (R_OBJY, C_OBJ, 0):
  926.         /* this might change which columns are used so erase all when
  927.          * returns and redraw if still on.
  928.          */
  929.         obj_setup (OBJY);
  930.         alt_nobody (OBJY);
  931.         if (obj_ison (OBJY)) {
  932.         oppl |= 1 << OBJY;
  933.         print_updating();
  934.         alt_body (OBJY, 1, &now);
  935.         } else
  936.         oppl &= ~(1 << OBJY);    /* already erased; just clear flag */
  937.         break;
  938.     case rcfpack (R_OBJY, C_CONSTEL, 0):
  939.         if (oppl & (1<<OBJY))
  940.         constellation_msg (OBJY, &now);
  941.         break;
  942.     }
  943.  
  944.     return (new);
  945. }
  946.  
  947. static
  948. print_tminc(force)
  949. int force;
  950. {
  951.     static double last = -123.456;    /* anything unlikely */
  952.  
  953.     if (force || tminc != last) {
  954.         if (tminc == RTC)
  955.         f_string (R_STPSZ, C_STPSZV, " RT CLOCK");
  956.         else if (fabs(tminc) >= 24.0)
  957.         f_double (R_STPSZ, C_STPSZV, "%6.4g dy", tminc/24.0);
  958.         else
  959.         f_signtime (R_STPSZ, C_STPSZV, tminc);
  960.         last = tminc;
  961.     }
  962. }
  963.  
  964. /* print stuff on bottom menu */
  965. static
  966. print_alt (howmuch)
  967. int howmuch;
  968. {
  969.     if (howmuch == 2)
  970.         alt_labels();
  971.     if (alt_menumask() == F_MNUJ)
  972.         altj_display (howmuch, &now);
  973.     else {
  974.         int p;
  975.         for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  976.         if (oppl & (1<<p))
  977.             alt_body (p, howmuch, &now);
  978.     }
  979. }
  980.  
  981. print_updating()
  982. {
  983.     f_prompt ("Updating...");
  984. }
  985.  
  986. static
  987. print_nstep(force)
  988. int force;
  989. {
  990.     static int last;
  991.  
  992.     if (force || nstep != last) {
  993.         char buf[16];
  994.         (void) sprintf (buf, "%8d", nstep);
  995.         f_string (R_NSTEP, C_NSTEPV, buf);
  996.         last = nstep;
  997.     }
  998. }
  999.  
  1000. static
  1001. print_spause(force)
  1002. int force;
  1003. {
  1004.     static int last;
  1005.  
  1006.     if (force || spause != last) {
  1007.         char buf[16];
  1008.         (void) sprintf (buf, "%8d", spause);
  1009.         f_string (R_PAUSE, C_PAUSEV, buf);
  1010.         last = spause;
  1011.     }
  1012. }
  1013.  
  1014. /* if not plotting/listing/searching then sleep spause seconds.
  1015.  * if time is being based on the real-time clock, sync on the next
  1016.  *   integral multiple of spause seconds after the minute.
  1017.  * check for keyboard action once each second to let it break out early.
  1018.  */
  1019. slp_sync()
  1020. {
  1021.     extern long time();
  1022.  
  1023.     if (spause > 0 && !plot_ison() && !srch_ison() && !listing_ison()) {
  1024.         int n;
  1025.         if (tminc == RTC) {
  1026.         long t;
  1027.         (void) time (&t);
  1028.         n = spause - (t % spause);
  1029.         } else 
  1030.         n = spause;
  1031.         while (--n >= 0)
  1032.         if (chk_char() == 0)
  1033.             break;
  1034.         else
  1035.             (void) sleep (1);
  1036.     }
  1037. }
  1038.  
  1039. static
  1040. toggle_body (p)
  1041. int p;
  1042. {
  1043.     if ((oppl ^= (1<<p)) & (1<<p)) {
  1044.         print_updating();
  1045.         alt_body (p, 1, &now);
  1046.     } else
  1047.         alt_nobody (p);
  1048. }
  1049.